package lock

import (
	"fmt"
	"sync"
)

type MyRwLock2 struct {
	mx *sync.Mutex

	readers int
	writing bool

	readerCond *sync.Cond
	writeCond  *sync.Cond
}

func NewMyRwLock() *MyRwLock2 {
	lock := &sync.Mutex{}
	return &MyRwLock2{
		mx:         lock,
		readers:    0,
		writing:    false,
		readerCond: sync.NewCond(lock),
		writeCond:  sync.NewCond(lock),
	}
}

func (rl *MyRwLock2) RLock() {
	rl.mx.Lock()
	defer rl.mx.Unlock()

	for rl.writing {
		rl.readerCond.Wait()
	}
	rl.readers++
}

func (rl *MyRwLock2) RUnLock() {
	rl.mx.Lock()
	defer rl.mx.Unlock()

	rl.readers--
	if rl.readers == 0 {
		rl.writeCond.Signal()
	}
}

func (rl *MyRwLock2) WriteLock() {
	rl.mx.Lock()
	defer rl.mx.Unlock()

	for rl.readers > 0 || rl.writing {
		rl.writeCond.Wait()
	}

	rl.writing = true
}

func (rl *MyRwLock2) WriteUnLock() {
	rl.mx.Lock()
	defer rl.mx.Unlock()

	rl.writing = false

	rl.readerCond.Broadcast()
	rl.writeCond.Signal()
}

var SharedData int

func NewTryMyRWLock() {
	rwLock := NewMyRwLock()
	// 写Share协程
	readerRoutingNum := 5
	writeRoutingNum := 5

	wg := sync.WaitGroup{}

	for i := 0; i < readerRoutingNum; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()

			rwLock.RLock()
			println(fmt.Sprintf("我是协程 %v, 我读取ShareData为：%v", id, SharedData))
			rwLock.RUnLock()
		}(i)
	}

	for i := 0; i < writeRoutingNum; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			rwLock.WriteLock()
			SharedData++
			println(fmt.Sprintf("我是协程 %v,       我更新ShareData为：%v", id, SharedData))
			rwLock.WriteUnLock()
		}(i)
	}

	wg.Wait()
	println("协程数据处理已经完成")
}
